/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

/*
 * NodeParametersComponent.java
 *
 * Created on 8/Dez/2011, 21:40:44
 */

package intopo.evogame.partnerselection.tools.config;

import intopo.evogame.partnerselection.config.TextConfigFilePlainPlayersEditor;
import intopo.evogame.partnerselection.config.TextConfigFilePlainPlayersEditor.GeographicPopulationParameters;
import intopo.evogame.partnerselection.config.TextConfigFilePlainPlayersEditor.NodeParameters;
import intopo.evogame.partnerselection.chromosome.Chromosome;
import intopo.game.Strategy;
import intopo.game.gui.AbstractStrategyEditorComponent;
import intopo.game.gui.ParsingException;
import java.awt.Component;
import javax.swing.event.TableModelListener;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableColumn;

/**
 * This component alows the user to edit the properties of a node in a geographic population.
 *
 * The properties are the the carrying capacity of the node and the players that are created in the first generation.
 *
 * @author <a href="mailto:mariano.pedro@gmail.com">Pedro Mariano</a>
 *
 * @version 1.0 8/Dez/2011
 */
public class NodeParametersComponent
	extends javax.swing.JPanel
{
	private TextConfigFilePlainPlayersEditor configFile;
	/**
	 * Node parameters shown in this component.
	 */
	private NodeParameters nodeParameters;
	/**
	 * Table model of the table that contains the data of the players in a node.
	 */
	private PlayersTableModel playersTableModel;
	/**
	 * The player strategy editor and renderer is used by the {@code JTable} to render and to edit cell contents and is used to obtain a strategy.
	 */
	transient private  AbstractStrategyEditorComponent strategyEditorRenderer;
	/**
	 * Creates new form NodeParametersComponent */
	public NodeParametersComponent ()
	{
		System.out.println ("NodeParametersComponent GUI constructor");
	}
	public NodeParametersComponent (Object o)
	{
		System.out.println ("NodeParametersComponent GUI constructor");
	}
	NodeParametersComponent (TextConfigFilePlainPlayersEditor configFile)
	{
		this.configFile = configFile;
		this.nodeParameters = configFile.getPopulation ().getNode (0, 0);
		playersTableModel = new PlayersTableModel ();
		initComponents ();
		PlayerChromosomeEditorRenderer er = new PlayerChromosomeEditorRenderer ();
		playersTable.setDefaultRenderer (TextConfigFilePlainPlayersEditor.Chromosome.class, er);
		playersTable.setDefaultEditor (TextConfigFilePlainPlayersEditor.Chromosome.class, er);
		this.setupStrategyEditorRenderer ();
		this.adjustColumnWidth ();
	}
	void setNode (NodeParameters nodeParameters)
	{
//		System.out.println (nodeParameters.toString ());
		this.nodeParameters = nodeParameters;
		this.nodeFormattedTextField.setValue (new Integer (nodeParameters.getCarryingCapacity ()));
		this.playersTableModel.fireTableDataChanged ();
//		this.adjustColumnWidth ();
	}
	/**
	 * Invoked when the user changed a property of the chromosome component. As the user may have changed the default genes property, we have to update the table structure.
	 * This is in turn requires to update column width.
	 */
	void genericChromosomeParametersChanged ()
	{
		this.playersTableModel.fireTableStructureChanged ();
		this.adjustColumnWidth ();
	}
	/**
	 * Invoked when the user changed the game.  Need to update the strategy editor and renderer.  This is in turn requires to update column width.
	 */
	void gameChanged ()
	{
		this.setupStrategyEditorRenderer ();
		this.playersTableModel.fireTableStructureChanged ();
		this.adjustColumnWidth ();
	}
	/**
	 * Called when the user changes the game or in the constructor.
	 * Update the editor and renderer for Strategy objects in the players table.
	 * Adjust the row height.
	 */
	private void setupStrategyEditorRenderer ()
	{
		this.strategyEditorRenderer = this.configFile.getDescription ().getStrategyEditorComponent ();
		PlayerStrategyEditorRenderer pser = new PlayerStrategyEditorRenderer (this.strategyEditorRenderer);
		playersTable.setDefaultEditor (TextConfigFilePlainPlayersEditor.Player.class, pser);
		playersTable.setDefaultRenderer (TextConfigFilePlainPlayersEditor.Player.class, pser);
		PlayerChromosomeComponent compo = new PlayerChromosomeComponent ();
		int rowHeight = Math.max (
			Math.max (
				compo.getHeight (),
				compo.getPreferredSize ().height
			),
			Math.max (
				this.strategyEditorRenderer.getHeight (),
				this.strategyEditorRenderer.getPreferredSize ().height
			)
		);
		rowHeight += 10; // extra space for borders
		this.playersTable.setRowHeight (rowHeight);
	}
	private void adjustColumnWidth ()
	{
		// adjust the size of column 0: player quantity
		TableColumn column = this.playersTable.getColumnModel ().getColumn (0);
		TableCellRenderer headerRenderer = this.playersTable.getTableHeader ().getDefaultRenderer ();
		if (headerRenderer != null && column != null) {
			Component comp = headerRenderer.getTableCellRendererComponent
				(this.playersTable, column.getHeaderValue (), true, true, -1, 0);
			int width = comp.getPreferredSize ().width;
			column.setMinWidth (width);
			column.setMaxWidth (width + 2);
		}
		else {
			System.err.println ("Could not adjust column");
		}
	}
	/**
	 * Table model that serves the table that contains the data of the players in a node.
	 * This data is the chromosome, the strategy and the quantity of a player.  The last value represents the number of copies of a player with the specified chromosome and strategy.
	 * The chromosome may be optional if the user wants the default chromosome.
	 *
	 * <p> The column that displays the strategy of a player is specially handled.  Since the strategy editor may not change the fields of a strategy reference, but instead return a new copy, the class of this column is
	 * {@code NodeParameters.Player.class}.  We pass a reference of this type to an instance of class {@code PlayerStrategyEditorRenderer}.  The methods of this class handle this reference.  They use the methods {@code getStrategy()} and {@code setStrategy(Strategy)} of class {@code NodeParameters.Player}
	 * to change the player's strategy.
	 */
	class PlayersTableModel
		extends javax.swing.table.AbstractTableModel
	{

		@Override
		public int getRowCount ()
		{
			return nodeParameters.getNumberPlayers ();
		}

		@Override
		public int getColumnCount () {
			if (Chromosome.Parameters.defaultGenes) {
				return 2;
			}
			else {
				return 3;
			}
		}

		@Override
		public String getColumnName (int columnIndex)
		{
			switch (columnIndex) {
			case 0:
				return "Quantity";
			case 1:
				if (Chromosome.Parameters.defaultGenes) {
					return "Strategy";
				}
				else {
					return "Chromosome";
				}
			case 2:
				return "Strategy";
			}
			throw new IllegalArgumentException ("Invalid column index for PlayersTableModel: " + columnIndex);
		}

		@Override
		public Class<?> getColumnClass (int columnIndex)
		{
			switch (columnIndex) {
			case 0:
				return Integer.class;
			case 1:
				if (Chromosome.Parameters.defaultGenes) {
					return TextConfigFilePlainPlayersEditor.Player.class;
				}
				else {
					return TextConfigFilePlainPlayersEditor.Chromosome.class;
				}
			case 2:
				return TextConfigFilePlainPlayersEditor.Player.class;
			}
			throw new IllegalArgumentException ("Invalid column index for PlayersTableModel: " + columnIndex);
		}

		@Override
		public boolean isCellEditable (int rowIndex, int columnIndex)
		{
			return true;
		}

		@Override
		public Object getValueAt (int rowIndex, int columnIndex)
		{
			switch (columnIndex) {
			case 0:
				return nodeParameters.getPlayer (rowIndex).getQuantity ();
			case 1:
				if (Chromosome.Parameters.defaultGenes) {
					return nodeParameters.getPlayer (rowIndex);
				}
				else {
					return nodeParameters.getPlayer (rowIndex).getChromosome ();
				}
			case 2:
				return nodeParameters.getPlayer (rowIndex);
			}
			throw new IllegalArgumentException ("Invalid column index for PlayersTableModel: " + columnIndex);
		}

		@Override
		public void setValueAt (Object aValue, int rowIndex, int columnIndex)
		{
			switch (columnIndex) {
			case 0:
				nodeParameters.getPlayer (rowIndex).setQuantity ((Integer) aValue);
				return ;
			case 1:
				if (Chromosome.Parameters.defaultGenes) {
					nodeParameters.getPlayer (rowIndex).setStrategy ((Strategy) aValue);
					return ;
				}
				else {
					nodeParameters.getPlayer (rowIndex).setChromosome ((TextConfigFilePlainPlayersEditor.Chromosome) aValue);
					return ;
				}
			case 2:
				nodeParameters.getPlayer (rowIndex).setStrategy ((Strategy) aValue);
				return ;
			}
			throw new IllegalArgumentException ("Invalid column index for PlayersTableModel: " + columnIndex);
		}
	}
    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
   // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
   private void initComponents() {
      java.awt.GridBagConstraints gridBagConstraints;

      javax.swing.JScrollPane playersScrollPane = new javax.swing.JScrollPane();
      playersTable = new javax.swing.JTable();
      otherParametersPanel = new javax.swing.JPanel();
      javax.swing.JLabel jLabel1 = new javax.swing.JLabel();
      nodeFormattedTextField = new javax.swing.JFormattedTextField();
      separator = new javax.swing.JSeparator();
      addPlayerButton = new javax.swing.JButton();
      deletePlayerButton = new javax.swing.JButton();

      setLayout(new java.awt.BorderLayout());

      playersTable.setModel(this.playersTableModel);
      playersScrollPane.setViewportView(playersTable);

      add(playersScrollPane, java.awt.BorderLayout.CENTER);

      otherParametersPanel.setLayout(new java.awt.GridBagLayout());

      jLabel1.setText("carrying capacity: ");
      otherParametersPanel.add(jLabel1, new java.awt.GridBagConstraints());

      nodeFormattedTextField.setColumns(5);
      nodeFormattedTextField.setValue(new Integer (this.nodeParameters.getCarryingCapacity ()));
      nodeFormattedTextField.addPropertyChangeListener(new java.beans.PropertyChangeListener() {
         public void propertyChange(java.beans.PropertyChangeEvent evt) {
            nodeFormattedTextFieldPropertyChange(evt);
         }
      });
      otherParametersPanel.add(nodeFormattedTextField, new java.awt.GridBagConstraints());

      separator.setOrientation(javax.swing.SwingConstants.VERTICAL);
      gridBagConstraints = new java.awt.GridBagConstraints();
      gridBagConstraints.fill = java.awt.GridBagConstraints.VERTICAL;
      gridBagConstraints.weightx = 0.1;
      otherParametersPanel.add(separator, gridBagConstraints);

      addPlayerButton.setText("Add");
      addPlayerButton.addActionListener(new java.awt.event.ActionListener() {
         public void actionPerformed(java.awt.event.ActionEvent evt) {
            addPlayerButtonActionPerformed(evt);
         }
      });
      otherParametersPanel.add(addPlayerButton, new java.awt.GridBagConstraints());

      deletePlayerButton.setText("Delete");
      deletePlayerButton.addActionListener(new java.awt.event.ActionListener() {
         public void actionPerformed(java.awt.event.ActionEvent evt) {
            deletePlayerButtonActionPerformed(evt);
         }
      });
      otherParametersPanel.add(deletePlayerButton, new java.awt.GridBagConstraints());

      add(otherParametersPanel, java.awt.BorderLayout.NORTH);
   }// </editor-fold>//GEN-END:initComponents

	 private void nodeFormattedTextFieldPropertyChange (java.beans.PropertyChangeEvent evt) {//GEN-FIRST:event_nodeFormattedTextFieldPropertyChange

		//System.out.println ("NodeParametersComponent#nodeFormattedTextField " + evt.getPropertyName ());
		if (evt.getPropertyName ().equals ("value")) {
			Integer newValue = (Integer) this.nodeFormattedTextField.getValue ();
			this.nodeParameters.setCarryingCapacity (newValue);
		}
	 }//GEN-LAST:event_nodeFormattedTextFieldPropertyChange

	 private void deletePlayerButtonActionPerformed (java.awt.event.ActionEvent evt) {//GEN-FIRST:event_deletePlayerButtonActionPerformed
		int row = this.playersTable.getSelectedRow ();
		this.nodeParameters.removePlayer (row);
		this.playersTableModel.fireTableRowsDeleted (row, row);
	 }//GEN-LAST:event_deletePlayerButtonActionPerformed

	 private void addPlayerButtonActionPerformed (java.awt.event.ActionEvent evt) {//GEN-FIRST:event_addPlayerButtonActionPerformed
		try {
			this.nodeParameters.addPlayer (this.strategyEditorRenderer.getStrategy ());
			int row = this.nodeParameters.getNumberPlayers () - 1;
			this.playersTableModel.fireTableRowsInserted (row, row);
		}
		catch (ParsingException e) {
			
		}
	 }//GEN-LAST:event_addPlayerButtonActionPerformed


   // Variables declaration - do not modify//GEN-BEGIN:variables
   private javax.swing.JButton addPlayerButton;
   private javax.swing.JButton deletePlayerButton;
   private javax.swing.JFormattedTextField nodeFormattedTextField;
   private javax.swing.JPanel otherParametersPanel;
   private javax.swing.JTable playersTable;
   private javax.swing.JSeparator separator;
   // End of variables declaration//GEN-END:variables

}

// Local Variables:
// mode: java
// mode: flyspell-prog
// ispell-local-dictionary: "british"
// End:
